package com.sinsz.c.mongo.base;

import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 公共的实现接口实现
 *
 * @author chenjianbo
 * @date 2017/11/14
 */
public class BaseMongoRepository<T, ID extends Serializable> extends SimpleMongoRepository<T, ID> implements
        IBaseMongoRepository<T, ID> {

    private final MongoOperations mongoTemplate;

    private final MongoEntityInformation<T, ID> mongoEntityInformation;

    public BaseMongoRepository(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {
        super(metadata, mongoOperations);
        this.mongoEntityInformation = metadata;
        this.mongoTemplate = mongoOperations;
    }

    private String getCn(){
        return mongoEntityInformation.getCollectionName();
    }

    private Class<T> getClz() {
        return mongoEntityInformation.getJavaType();
    }

    private <S> List<S> conver(List<T> list, Class<S> clz) {
        List<S> result = new ArrayList<>();
        if (ObjectUtils.isEmpty(list)) {
            return result;
        }
        result = list.stream()
                .map(t -> {
                    S s = null;
                    try {
                        s = clz.newInstance();
                        BeanUtils.copyProperties(t, s);
                    } catch (InstantiationException | IllegalAccessException e) {
                        e.printStackTrace(System.out);
                    }
                    return s;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        return result;
    }

    @Override
    public <S> S getOne(ID id, Class<S> clz) {
        S s = null;
        try {
            T t = mongoTemplate.findOne(
                    new Query(Criteria.where(
                            mongoEntityInformation.getIdAttribute()
                    ).is(id)),
                    getClz(),
                    getCn()
            );
            s = clz.newInstance();
            BeanUtils.copyProperties(t, s);
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace(System.out);
        }
        return s;
    }

    @Override
    public <S> List<S> getBatch(Query query, Class<S> clz) {
        return conver(
                mongoTemplate.find(query, getClz(), getCn()),
                clz
        );
    }

    @Override
    public <S> List<S> getAll(Class<S> clz) {
        return conver(
                mongoTemplate.findAll(getClz(), getCn()),
                clz
        );
    }

    @Override
    public <S> Page<S> getPage(Query query, Pageable pageable, Class<S> clz) {
        long total = mongoTemplate.count(query, getClz());
        List<S> list = getBatch(query.with(pageable), clz);
        return new PageImpl<S>(list, pageable, total);
    }

}